﻿#include <opencv2/imgproc/imgproc.hpp>    
#include <opencv2/core/core.hpp>          
#include <opencv2/highgui/highgui.hpp>   
#include <math.h>
#include <iostream>

using namespace cv;
using namespace std;
float M_PI = 3.14159265358979323846f;
float faceTransform[6][2] =
{
	{0, 0},
	{M_PI / 2,0},
	{M_PI,0},
	{-M_PI / 2,0},
	{0,-M_PI / 2},
	{0,M_PI / 2}
};


inline void createCubeMapFace(const Mat &in, Mat &face, vector<string> &imageFilePath, int faceId = 0,  const int width = -1, const int height = -1)
{

	float inWidth = in.cols;
	float inHeight = in.rows;     // 获取图片的行列数量

//  cout << in.cols;
//  cout << in.rows;
//  system("pause");
	// Allocate map
	Mat mapx(height, width, CV_32F);
	Mat mapy(height, width, CV_32F);                                         //分配图的x,y轴


	// Calculate adjacent (ak) and opposite (an) of the
	// triangle that is spanned from the sphere center 
	//to our cube face.
	const float an = sin(M_PI / 4);
	const float ak = cos(M_PI / 4);                                          //计算相邻ak和相反an的三角形张成球体中心

//  cout << ak;
//  cout << an;
//  system("pause");
	const float ftu = faceTransform[faceId][0];
	const float ftv = faceTransform[faceId][1];

	// For each point in the target image, 
	// calculate the corresponding source coordinates.                      对于每个图像计算相应的源坐标
	for (int y = 0; y < height; y++) {
		for (int x = 0; x < width; x++) {

			// Map face pixel coordinates to [-1, 1] on plane               将坐标映射在平面上
			float nx = (float)y / (float)height - 0.5f;
			float ny = (float)x / (float)width - 0.5f;

			nx *= 2;
			ny *= 2;

			// Map [-1, 1] plane coord to [-an, an]                          
			// thats the coordinates in respect to a unit sphere 
			// that contains our box. 
			nx *= an;
			ny *= an;

			float u, v;

			// Project from plane to sphere surface.
			if (ftv == 0) {
				// Center faces
				u = atan2(nx, ak);
				v = atan2(ny * cos(u), ak);
				u += ftu;
			}
			else if (ftv > 0) {
				// Bottom face 
				float d = sqrt(nx * nx + ny * ny);
				v = M_PI / 2 - atan2(d, ak);
				u = atan2(ny, nx);
			}
			else {
				// Top face
				//cout << "aaa";
				float d = sqrt(nx * nx + ny * ny);
				v = -M_PI / 2 + atan2(d, ak);
				u = atan2(-ny, nx);
			}

			// Map from angular coordinates to [-1, 1], respectively.
			u = u / (M_PI);
			v = v / (M_PI / 2);

			// Warp around, if our coordinates are out of bounds. 
			while (v < -1) {
				v += 2;
				u += 1;
			}
			while (v > 1) {
				v -= 2;
				u += 1;
			}

			while (u < -1) {
				u += 2;
			}
			while (u > 1) {
				u -= 2;
			}

			// Map from [-1, 1] to in texture space
			u = u / 2.0f + 0.5f;
			v = v / 2.0f + 0.5f;

			u = u * (inWidth - 1);
			v = v * (inHeight - 1);

			mapx.at<float>(x, y) = u;
			mapy.at<float>(x, y) = v;
		}
	}

	// Recreate output image if it has wrong size or type. 
	if (face.cols != width || face.rows != height ||
		face.type() != in.type()) {
		face = Mat(width, height, in.type());
		/*  system("pause");*/
	}

	// Do actual  using OpenCV's remap
	remap(in, face, mapx, mapy, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));
	//  imshow("123", in);
	//  imshow("456", face);

	if (faceId == 0)
	{
		imwrite("E:\\cube0000.jpg", face);
		imageFilePath.push_back("E:\\cube0000.jpg");
	}
	else if (faceId == 1)
	{
		imwrite("E:\\cube0004.jpg", face);
		imageFilePath.push_back("E:\\cube0004.jpg");
	}
	else if (faceId == 2)
	{
		imwrite("E:\\cube0001.jpg", face);
		imageFilePath.push_back("E:\\cube0001.jpg");
	}
	else if (faceId == 3)
	{
		imwrite("E:\\cube0005.jpg", face);
		imageFilePath.push_back("E:\\cube0005.jpg");
	}
	else if (faceId == 4)
	{
		imwrite("E:\\cube0002.jpg", face);
		imageFilePath.push_back("E:\\cube0002.jpg");
	}
	else if (faceId == 5)
	{
		imwrite("E:\\cube0003.jpg", face);
		imageFilePath.push_back("E:\\cube0003.jpg");
	}
	

	/*  waitKey(10000);*/

}

inline void stitchImage(vector<string> &imageFilePath)
{
	//读入八幅图片
	Mat image_0 = imread(imageFilePath[0]);
	Mat image_1 = imread(imageFilePath[2]);
	Mat image_2 = imread(imageFilePath[4]);
	Mat image_3 = imread(imageFilePath[5]);
	Mat image_4 = imread(imageFilePath[1]);
	Mat image_5 = imread(imageFilePath[3]);
	Mat image_6 = imread(imageFilePath[3]);
	Mat image_7 = imread(imageFilePath[3]);


	//归一化为相同的大小：1024*1024
	Size sz = Size(1024, 1024);
	resize(image_0, image_0, sz);
	resize(image_1, image_1, sz);
	resize(image_2, image_2, sz);
	resize(image_3, image_3, sz);
	resize(image_4, image_4, sz);
	resize(image_5, image_5, sz);
	resize(image_6, image_6, sz);
	resize(image_7, image_7, sz);

	//创建连接后存入的图像
	Mat result(sz.height, sz.width * 8, image_1.type());

	//四幅图像拷贝,中间的一行（列）作为图像间分割线
	//第0幅，拷贝到左上角
	Rect roi_rect = Rect(0, 0, sz.width, sz.height);
	image_0.copyTo(result(roi_rect));

	//四幅图像拷贝,中间的一行（列）作为图像间分割线
	//第1幅，拷贝到左上角
	roi_rect = Rect(sz.width, 0, sz.width, sz.height);
	image_1.copyTo(result(roi_rect));

	//第2幅，拷贝到右上角
	roi_rect = Rect(sz.width*2, 0, sz.width, sz.height);
	image_2.copyTo(result(roi_rect));

	//第3幅，拷贝到左下角
	roi_rect = Rect(sz.width*3, 0, sz.width, sz.height);
	image_3.copyTo(result(roi_rect));

	//第4幅，拷贝到右下角
	roi_rect = Rect(sz.width*4,0, sz.width, sz.height);
	image_4.copyTo(result(roi_rect));

	//第5幅，拷贝到右下角
	roi_rect = Rect(sz.width*5, 0, sz.width, sz.height);
	image_5.copyTo(result(roi_rect));

	//Mat img = image_5.clone();
	////if (img.channels() > 1)
	////{
	////	cvtColor(img, img, COLOR_RGB2GRAY);
	////}
	//Mat out(img.size(), img.type(), Scalar(0));//全黑图

	//Mat m1 = Mat(1024, 1024, CV_8UC3, Scalar(0, 255, 255));

	roi_rect = Rect(sz.width * 6, 0, sz.width, sz.height);
	image_6.copyTo(result(roi_rect));

	roi_rect = Rect(sz.width * 7, 0, sz.width, sz.height);
	image_7.copyTo(result(roi_rect));

	imwrite("E:\\result.jpg", result);
}


int main()
{

	int faceId = 0;
	int width = 1296;
	int height = 1296;
	cv::Mat srcimage = cv::imread("E:\\00000272.jpg");
	cv::Mat resultImage;



	vector<string> imageFilePath;

	for (int i = 0; i < 6; i++) {
		createCubeMapFace(srcimage, resultImage, imageFilePath, i, width, height);
	}

	stitchImage(imageFilePath);
}